package cosclient

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/tencentyun/cos-go-sdk-v5"

	configpkg "github.com/liyixin123/my-cos-project/internal/config"
)

// Client 云存储客户端接口
type Client interface {
	TestConnection() error
	ListFiles(directory string) ([]*FileInfo, error)
	UploadFile(key, filePath string) error
	DownloadFile(key, filePath string) error
	DeleteFile(key string) error
	GetFileURL(key string) string
}

// COSClient COS客户端封装
type COSClient struct {
	client *cos.Client
	config *configpkg.Config
}

// S3Client AWS S3客户端封装
type S3Client struct {
	client *s3.S3
	config *configpkg.Config
}

// FileInfo 文件信息
type FileInfo struct {
	Name         string `json:"name"`
	Key          string `json:"key"`
	Size         int64  `json:"size"`
	LastModified string `json:"last_modified"`
	Directory    string `json:"directory"`
	URL          string `json:"url"`
}

// NewClient 创建云存储客户端 (自动根据配置选择COS或S3)
func NewClient(cfg *configpkg.Config) (Client, error) {
	if cfg.IsS3() {
		return NewS3Client(cfg)
	}
	return NewCOSClient(cfg)
}

// NewCOSClient 创建COS客户端
func NewCOSClient(cfg *configpkg.Config) (*COSClient, error) {
	if cfg.SecretID == "" || cfg.SecretKey == "" ||
		cfg.Bucket == "" || cfg.Region == "" {
		return nil, fmt.Errorf("配置信息不完整")
	}

	var bucketURL *url.URL
	var err error

	// 如果提供了自定义端点，则使用它
	if cfg.Endpoint != "" {
		bucketURL, err = url.Parse(fmt.Sprintf("%s/%s", cfg.Endpoint, cfg.Bucket))
	} else {
		bucketURL, err = url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", cfg.Bucket, cfg.Region))
	}

	if err != nil {
		return nil, err
	}

	b := &cos.BaseURL{BucketURL: bucketURL}
	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  cfg.SecretID,
			SecretKey: cfg.SecretKey,
		},
	})

	return &COSClient{
		client: client,
		config: cfg,
	}, nil
}

// NewS3Client 创建S3客户端
func NewS3Client(cfg *configpkg.Config) (*S3Client, error) {
	if cfg.SecretID == "" || cfg.SecretKey == "" ||
		cfg.Bucket == "" || cfg.Region == "" {
		return nil, fmt.Errorf("配置信息不完整")
	}

	// AWS配置
	awsConfig := &aws.Config{
		Region: aws.String(cfg.Region),
		Credentials: credentials.NewStaticCredentials(
			cfg.SecretID,  // AccessKeyId
			cfg.SecretKey, // SecretAccessKey
			""),           // Token (留空)
	}

	// 如果提供了自定义端点，则设置
	if cfg.Endpoint != "" {
		awsConfig.Endpoint = aws.String(cfg.Endpoint)
	}

	sess, err := session.NewSession(awsConfig)
	if err != nil {
		return nil, err
	}

	return &S3Client{
		client: s3.New(sess),
		config: cfg,
	}, nil
}

// TestConnection 测试连接
func (c *COSClient) TestConnection() error {
	opt := &cos.BucketGetOptions{
		MaxKeys: 1,
	}

	_, resp, err := c.client.Bucket.Get(context.Background(), opt)
	if err != nil {
		// 尝试提供更多错误信息
		if resp != nil && resp.StatusCode != 0 {
			return fmt.Errorf("COS连接失败 (HTTP %d): %w", resp.StatusCode, err)
		}
		return fmt.Errorf("COS连接失败: %w", err)
	}
	return nil
}

// TestConnection 测试S3连接
func (s *S3Client) TestConnection() error {
	result, err := s.client.ListObjectsV2(&s3.ListObjectsV2Input{
		Bucket:  aws.String(s.config.Bucket),
		MaxKeys: aws.Int64(1),
	})

	if err != nil {
		// 尝试提供更多错误信息
		if awsErr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("S3连接失败 [%s]: %s (原始错误: %w)", awsErr.Code(), awsErr.Message(), err)
		}
		return fmt.Errorf("S3连接失败: %w", err)
	}

	// 检查结果是否有效
	if result == nil {
		return fmt.Errorf("S3连接失败: 空响应")
	}

	return nil
}

// ListFiles 列出文件
func (c *COSClient) ListFiles(directory string) ([]*FileInfo, error) {
	var files []*FileInfo

	// 如果指定目录，列出该目录的文件
	if directory != "" {
		opt := &cos.BucketGetOptions{
			Prefix:  directory + "/",
			MaxKeys: 1000,
		}

		result, _, err := c.client.Bucket.Get(context.Background(), opt)
		if err != nil {
			return nil, err
		}

		for _, content := range result.Contents {
			fileName := strings.TrimPrefix(content.Key, directory+"/")
			if fileName == "" { // 跳过目录本身
				continue
			}

			files = append(files, &FileInfo{
				Name:         fileName,
				Key:          content.Key,
				Size:         content.Size,
				LastModified: content.LastModified,
				Directory:    directory,
				URL:          c.getFileURL(content.Key),
			})
		}
	} else {
		// 列出所有目录中的文件
		allDirs := []string{"images", "documents", "audio", "videos", "archives", "code", "others"}
		for _, dir := range allDirs {
			opt := &cos.BucketGetOptions{
				Prefix:  dir + "/",
				MaxKeys: 1000,
			}

			result, _, err := c.client.Bucket.Get(context.Background(), opt)
			if err != nil {
				// 忽略单个目录的错误，继续处理其他目录
				continue
			}

			for _, content := range result.Contents {
				fileName := strings.TrimPrefix(content.Key, dir+"/")
				if fileName == "" { // 跳过目录本身
					continue
				}

				files = append(files, &FileInfo{
					Name:         fileName,
					Key:          content.Key,
					Size:         content.Size,
					LastModified: content.LastModified,
					Directory:    dir,
					URL:          c.getFileURL(content.Key),
				})
			}
		}
	}

	return files, nil
}

// ListFiles 列出S3文件
func (s *S3Client) ListFiles(directory string) ([]*FileInfo, error) {
	var files []*FileInfo

	if directory != "" {
		result, err := s.client.ListObjectsV2(&s3.ListObjectsV2Input{
			Bucket:  aws.String(s.config.Bucket),
			Prefix:  aws.String(directory + "/"),
			MaxKeys: aws.Int64(1000),
		})
		if err != nil {
			return nil, err
		}

		for _, obj := range result.Contents {
			key := *obj.Key
			fileName := strings.TrimPrefix(key, directory+"/")
			if fileName == "" { // Skip directory itself
				continue
			}

			files = append(files, &FileInfo{
				Name:         fileName,
				Key:          key,
				Size:         *obj.Size,
				LastModified: obj.LastModified.Format(time.RFC3339),
				Directory:    directory,
				URL:          s.GetFileURL(key),
			})
		}
	} else {
		// List files from all directories
		allDirs := []string{"images", "documents", "audio", "videos", "archives", "code", "others"}
		for _, dir := range allDirs {
			result, err := s.client.ListObjectsV2(&s3.ListObjectsV2Input{
				Bucket:  aws.String(s.config.Bucket),
				Prefix:  aws.String(dir + "/"),
				MaxKeys: aws.Int64(1000),
			})
			if err != nil {
				continue
			}

			for _, obj := range result.Contents {
				key := *obj.Key
				fileName := strings.TrimPrefix(key, dir+"/")
				if fileName == "" { // Skip directory itself
					continue
				}

				files = append(files, &FileInfo{
					Name:         fileName,
					Key:          key,
					Size:         *obj.Size,
					LastModified: obj.LastModified.Format(time.RFC3339),
					Directory:    dir,
					URL:          s.GetFileURL(key),
				})
			}
		}
	}

	return files, nil
}

// UploadFile 上传文件
func (c *COSClient) UploadFile(key, filePath string) error {
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = c.client.Object.Put(context.Background(), key, file, nil)
	return err
}

// UploadFile 上传文件到S3
func (s *S3Client) UploadFile(key, filePath string) error {
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	fileInfo, err := file.Stat()
	if err != nil {
		return err
	}

	_, err = s.client.PutObject(&s3.PutObjectInput{
		Bucket:        aws.String(s.config.Bucket),
		Key:           aws.String(key),
		Body:          file,
		ContentLength: aws.Int64(fileInfo.Size()),
	})
	return err
}

// DownloadFile 下载文件
func (c *COSClient) DownloadFile(key, filePath string) error {
	resp, err := c.client.Object.Get(context.Background(), key, nil)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	outFile, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer outFile.Close()

	_, err = io.Copy(outFile, resp.Body)
	return err
}

// DownloadFile 从S3下载文件
func (s *S3Client) DownloadFile(key, filePath string) error {
	result, err := s.client.GetObject(&s3.GetObjectInput{
		Bucket: aws.String(s.config.Bucket),
		Key:    aws.String(key),
	})
	if err != nil {
		return err
	}
	defer result.Body.Close()

	outFile, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer outFile.Close()

	_, err = io.Copy(outFile, result.Body)
	return err
}

// DeleteFile 删除文件
func (c *COSClient) DeleteFile(key string) error {
	_, err := c.client.Object.Delete(context.Background(), key)
	return err
}

// DeleteFile 删除S3文件
func (s *S3Client) DeleteFile(key string) error {
	_, err := s.client.DeleteObject(&s3.DeleteObjectInput{
		Bucket: aws.String(s.config.Bucket),
		Key:    aws.String(key),
	})
	return err
}

// GetFileURL 获取文件访问URL
func (c *COSClient) GetFileURL(key string) string {
	return c.getFileURL(key)
}

// GetFileURL 获取S3文件访问URL
func (s *S3Client) GetFileURL(key string) string {
	if s.config == nil {
		return ""
	}

	if s.config.Endpoint != "" {
		base := strings.TrimRight(s.config.Endpoint, "/")
		return fmt.Sprintf("%s/%s/%s", base, s.config.Bucket, key)
	}

	return fmt.Sprintf("https://%s.s3.%s.amazonaws.com/%s", s.config.Bucket, s.config.Region, key)
}

// getFileURL 构建COS文件访问URL
func (c *COSClient) getFileURL(key string) string {
	if c.config.Endpoint != "" {
		return fmt.Sprintf("%s/%s", c.config.Endpoint, key)
	}
	return fmt.Sprintf("https://%s.cos.%s.myqcloud.com/%s", c.config.Bucket, c.config.Region, key)
}

